package com.cj.mobile.iabp.app.global;

import static com.cj.mobile.iabp.BuildConfig.DEBUG;

import android.app.Application;
import android.content.Context;
import android.text.TextUtils;

import androidx.annotation.NonNull;
import androidx.fragment.app.FragmentManager;

import com.cj.mobile.iabp.app.config.ActivityLifecycleCallbacksImpl;
import com.cj.mobile.iabp.app.config.AppLifecyclesImpl;
import com.cj.mobile.iabp.app.config.FragmentLifecycleCallbacksImpl;
import com.cj.mobile.iabp.app.config.GlobalHttpHandlerImpl;
import com.cj.mobile.iabp.app.config.ResponseErrorListenerImpl;
import com.cj.mobile.iabp.app.config.SSLSocketClient;
import com.jess.arms.base.delegate.AppLifecycles;
import com.jess.arms.di.module.GlobalConfigModule;
import com.jess.arms.http.imageloader.glide.GlideImageLoaderStrategy;
import com.jess.arms.http.log.FormatPrinter;
import com.jess.arms.http.log.RequestInterceptor;
import com.jess.arms.integration.ConfigModule;

import java.util.List;
import java.util.concurrent.TimeUnit;

import me.jessyan.progressmanager.ProgressManager;
import me.jessyan.retrofiturlmanager.RetrofitUrlManager;
import okhttp3.MediaType;
import okhttp3.Request;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;
import timber.log.Timber;

/**
 * 包名： com.zqw.mobile.recyclingandroid.app.global
 * 对象名： GlobalConfiguration
 * 描述：app 的全局配置信息在此配置,需要将此实现类声明到 AndroidManifest 中
 * 作者： wly
 * 邮箱：wangliyang206@163.com
 * 创建日期： 2017/9/22 12:24
 */

public class GlobalConfiguration implements ConfigModule {

    /**
     * 使用builder可以为框架配置一些配置信息
     */
    @Override
    public void applyOptions(@NonNull Context context, @NonNull GlobalConfigModule.Builder builder) {

        //Release 时
        if (!DEBUG) {
            //让框架不再打印 Http 请求和响应的信息
            builder.printHttpLogLevel(RequestInterceptor.Level.NONE);
        }

        // 获取动态配置的地址
        AccountManager mAccountManager = new AccountManager(context);
        // 如果没有配置服务器地址，则配置默认地址。
        if (TextUtils.isEmpty(mAccountManager.getServiceUrl())) {
            if (DEBUG) {
                // 测试地址
                mAccountManager.setServiceUrl(Constant.ROUTING_MAN_URL_1);
            } else {
                // 正式地址
                mAccountManager.setServiceUrl(Constant.IABP_SERVER_URL);
            }

        }
        //配置服务请求地址
        builder.baseurl(mAccountManager.getServiceUrl())

                //强烈建议自己自定义图片加载逻辑,因为默认提供的 GlideImageLoaderStrategy 并不能满足复杂的需求
                //请参考 https://github.com/JessYanCoding/MVPArms/wiki#3.4
                .imageLoaderStrategy(new GlideImageLoaderStrategy())

                //可根据当前项目的情况以及环境为框架某些部件提供自定义的缓存策略, 具有强大的扩展性
//                .cacheFactory(new Cache.Factory() {
//                    @NonNull
//                    @Override
//                    public Cache build(CacheType type) {
//                        switch (type.getCacheTypeId()){
//                            case CacheType.EXTRAS_TYPE_ID:
//                                return new LruCache(1000);
//                            case CacheType.CACHE_SERVICE_CACHE_TYPE_ID:
//                                return new Cache(type.calculateCacheSize(context));               // 自定义 Cache
//                            default:
//                                return new LruCache(200);
//                        }
//                    }
//                })


                //若觉得框架默认的打印格式并不能满足自己的需求, 可自行扩展自己理想的打印格式 (以下只是简单实现)
                .formatPrinter(new FormatPrinter() {
                    @Override
                    public void printJsonRequest(Request request, String bodyString) {
                        Timber.i("请求地址：%s", request.url());
                        Timber.i("请求参数：%s", bodyString);
                    }

                    @Override
                    public void printFileRequest(Request request) {
                        Timber.i("请求地址：%s", request.url().toString());
                    }

                    @Override
                    public void printJsonResponse(long chainMs, boolean isSuccessful, int code,
                                                  String headers, MediaType contentType, String bodyString,
                                                  List<String> segments, String message, String responseUrl) {
                        Timber.i("响应地址：%s", responseUrl + " (" + chainMs + "ms)");
                        Timber.i("响应参数：%s", bodyString);
                    }

                    @Override
                    public void printFileResponse(long chainMs, boolean isSuccessful, int code, String headers,
                                                  List<String> segments, String message, String responseUrl) {
                        Timber.i("响应地址：%s", responseUrl + " (" + chainMs + "ms)");
                    }
                })

                // 这里提供一个全局处理 Http 请求和响应结果的处理类,可以比客户端提前一步拿到服务器返回的结果,可以做一些操作,比如token超时,重新获取
                .globalHttpHandler(new GlobalHttpHandlerImpl(context))
                // rxjava必要要使用ErrorHandleSubscriber(默认实现Subscriber的onError方法),此监听才生效
                .responseErrorListener(new ResponseErrorListenerImpl())
                //这里可以自己自定义配置Gson的参数
                .gsonConfiguration((context1, gsonBuilder) -> {
                    gsonBuilder
                            //支持序列化null的参数
                            .serializeNulls()
                            //支持将序列化key为object的map,默认只能序列化key为string的map
                            .enableComplexMapKeySerialization();
                })
                //这里可以自己自定义配置Retrofit的参数,甚至你可以替换系统配置好的okhttp对象
                .retrofitConfiguration((context1, retrofitBuilder) -> {
                    //比如使用fastjson替代gson
//                    retrofitBuilder.addConverterFactory(FastJsonConverterFactory.create());
                    retrofitBuilder.addConverterFactory(GsonConverterFactory.create());
                    retrofitBuilder.addCallAdapterFactory(RxJava2CallAdapterFactory.create());
                })
                //这里可以自己自定义配置Okhttp的参数
                .okhttpConfiguration((context1, okhttpBuilder) -> {
                    //支持 Https,详情请百度
                    okhttpBuilder.sslSocketFactory(SSLSocketClient.getSSLSocketFactory(), SSLSocketClient.getTrustManager());
                    okhttpBuilder.hostnameVerifier(SSLSocketClient.getHostnameVerifier());
                    //请求超时
                    okhttpBuilder.connectTimeout(40, TimeUnit.SECONDS);
                    //写入超时
                    okhttpBuilder.writeTimeout(30, TimeUnit.SECONDS);
                    //读取超时
                    okhttpBuilder.readTimeout(30, TimeUnit.SECONDS);
                    //使用一行代码监听 Retrofit／Okhttp 上传下载进度监听,以及 Glide 加载进度监听 详细使用方法查看 https://github.com/JessYanCoding/ProgressManager
                    ProgressManager.getInstance().with(okhttpBuilder);
                    //让 Retrofit 同时支持多个 BaseUrl 以及动态改变 BaseUrl. 详细使用请方法查看 https://github.com/JessYanCoding/RetrofitUrlManager
                    RetrofitUrlManager.getInstance().with(okhttpBuilder);
                })
                //这里可以自己自定义配置RxCache的参数
                .rxCacheConfiguration((context1, rxCacheBuilder) -> {
                    //这里可以自己自定义配置 RxCache 的参数
                    rxCacheBuilder.useExpiredDataIfLoaderNotAvailable(true);
                    // 想自定义 RxCache 的缓存文件夹或者解析方式, 如改成 fastjson, 请 return rxCacheBuilder.persistence(cacheDirectory, new FastJsonSpeaker());
                    // 否则请 return null;
                    return null;
                })
                .cacheFile(context.getCacheDir());
    }

    /**
     * 向Application的生命周期中注入一些自定义逻辑
     */
    @Override
    public void injectAppLifecycle(@NonNull Context context, @NonNull List<AppLifecycles> lifecycles) {
        // AppLifecycles 的所有方法都会在基类 Application 的对应的生命周期中被调用,所以在对应的方法中可以扩展一些自己需要的逻辑
        // 可以根据不同的逻辑添加多个实现类
        lifecycles.add(new AppLifecyclesImpl());
    }

    /**
     * 向Activity的生命周期中注入一些自定义逻辑
     */
    @Override
    public void injectActivityLifecycle(@NonNull Context context, @NonNull List<Application.ActivityLifecycleCallbacks> lifecycles) {
        // ActivityLifecycleCallbacks 的所有方法都会在 Activity (包括三方库) 的对应的生命周期中被调用,所以在对应的方法中可以扩展一些自己需要的逻辑
        // 可以根据不同的逻辑添加多个实现类
        lifecycles.add(new ActivityLifecycleCallbacksImpl());
    }

    /**
     * 向Fragment的生命周期中注入一些自定义逻辑
     */
    @Override
    public void injectFragmentLifecycle(@NonNull Context context, @NonNull List<FragmentManager.FragmentLifecycleCallbacks> lifecycles) {
        //向Fragment的生命周期中注入一些自定义逻辑
        lifecycles.add(new FragmentLifecycleCallbacksImpl());
    }
}
